package com.zmjmall.demo.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zmjmall.demo.api.UserService;
import com.zmjmall.demo.async.AsyncTask;
import com.zmjmall.demo.constant.CookieConstant;
import com.zmjmall.demo.constant.RedisConstant;
import com.zmjmall.demo.dto.LoginDTO;
import com.zmjmall.demo.dto.LoginPasswordDTO;
import com.zmjmall.demo.enums.ResultEnum;
import com.zmjmall.demo.exception.MallAuthorizeException;
import com.zmjmall.demo.model.User;
import com.zmjmall.demo.util.CookieUtil;
import com.zmjmall.demo.util.RandomUtils;
import com.zmjmall.demo.util.UUIDUtil;
import com.zmjmall.demo.utils.ResultVOUtil;
import com.zmjmall.demo.utils.ValidatorUtil;
import com.zmjmall.demo.validator.IsMobile;
import com.zmjmall.demo.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 登录控制层
 *
 * @author zmj
 * @version 2018/7/3
 */
@RestController
@RequestMapping("/login")
@Slf4j
public class LoginController {

    @Reference
    private UserService userService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private AsyncTask asyncTask;

    /**
     * 注册账号
     * @param user
     * @return
     */
    @PostMapping("/register")
    @ResponseBody
    public ResultVO create(@Valid User user,@IsMobile @RequestParam(value = "code",required = true
    ) String code,HttpServletResponse response,HttpServletRequest request) {
        String redisCode = stringRedisTemplate.opsForValue().get(
                RedisConstant.REGISTER_CODE_PREFIX + user.getPhone());
        if(StringUtils.isNotBlank(redisCode)) {
            if(code.equals(redisCode)) {
                if(userService.insert(user)) {
                    generatorToken(request,response,user);
                    return  ResultVOUtil.success(ResultEnum.SUCCESS);
                }
                return  ResultVOUtil.error(ResultEnum.REGISTER_ISHAVE);
            }
        }
        throw new MallAuthorizeException(ResultEnum.LOGIN_CODE_ERROR);
    }

    /**
     * 用户登录 手机 + code 登录
     *
     * @param loginDTO
     * @return
     */
    @PostMapping
    @ResponseBody
    public ResultVO<String>  loginByCode(@Valid LoginDTO loginDTO, HttpServletResponse response,
                                   HttpServletRequest request) {

        String redisCode = stringRedisTemplate.opsForValue().get(
                RedisConstant.LOGIN_CODE_PREFIX + loginDTO.getPhone());

        if(StringUtils.isNotBlank(redisCode)) {
            if(loginDTO.getCode().equals(redisCode)) {
                User user = userService.getByPhone(loginDTO.getPhone());
                generatorToken(request,response,user);
                return ResultVOUtil.success(user);
            }
        }
        throw new MallAuthorizeException(ResultEnum.LOGIN_CODE_ERROR);
    }

    /**
     * 用户登录  账号+密码登录
     *
     * @param loginPasswordDTO
     * @return
     */
    @PostMapping("/byPssword")
    @ResponseBody
    public ResultVO<String>  loginByPssword(@Valid LoginPasswordDTO loginPasswordDTO, HttpServletResponse response,
                                            HttpServletRequest request) {

        User user = userService.loginByPssword(loginPasswordDTO);
        if(user == null) {
            return ResultVOUtil.error(ResultEnum.LOGIN_ERROR);
        }
        generatorToken(request,response,user);
        return ResultVOUtil.success(user);

    }

    /**
     * 获取登录验证码
     *
     * @param mobile
     * @return
     */
    @PostMapping(value = "/getLoginCode/{mobile}")
    public ResultVO<User>  getLoginCode(@IsMobile @PathVariable("mobile")String mobile) {

        User user = userService.getByPhone(mobile);
        if(null != user){
            String code = RandomUtils.generateNumber(6);
            generatorCode(RedisConstant.LOGIN_CODE_PREFIX,user.getPhone(),code);
            return ResultVOUtil.success(code);
        }
        return ResultVOUtil.error(ResultEnum.LOGIN_NOT_REGISTER);
    }

    /**
     * 获取注册验证码
     *
     * @param phone
     * @return
     */
    @PostMapping(value = "/getRegisterCode/{phone}")
    public synchronized ResultVO<User>  getRegisterCode( @PathVariable @RequestParam(value = "phone",required = true) String phone) {
        if(!ValidatorUtil.isMobile(phone)){
            throw new MallAuthorizeException(ResultEnum.MOBILE_EERROR);
        }
        User byPhone = userService.getByPhone(phone);
        if(byPhone != null) {
            return ResultVOUtil.error(ResultEnum.REGISTER_ISHAVE);
        }
        String code = RandomUtils.generateNumber(6);
        generatorCode(RedisConstant.REGISTER_CODE_PREFIX,phone,code);
        return ResultVOUtil.success(code);
    }

    /**
     * 生成验证码
     * code存入redis
     * @param keyPrefix
     * @param phone
     * @param code
     */
    private void generatorCode(String keyPrefix,String phone,String code) {
       stringRedisTemplate.opsForValue().set(keyPrefix + phone,
               code,RedisConstant.CODE_EXPIRE, TimeUnit.SECONDS);
    }

    /**
     * 生成token
     * @param request
     * @param response
     * @param user
     * @return
     */
    private String generatorToken(HttpServletRequest request,HttpServletResponse response,User user) {
        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
        String cookieToken = "";
        if(null != cookie) {
            cookieToken = cookie.getValue();
        }else{
            //生成cookie
            cookieToken = UUIDUtil.uuid();
            CookieUtil.set(response, CookieConstant.TOKEN,cookieToken, RedisConstant.EXPIRE);
        }
        //redis 用户信息
        String redisUserInfo = stringRedisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookieToken));
        try {

            if(StringUtils.isEmpty(redisUserInfo)) {
                //根据token生成redis缓存用户信息
                redisUserInfo = objectMapper.writeValueAsString(user);
                stringRedisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX,cookieToken),redisUserInfo,RedisConstant.EXPIRE,TimeUnit.SECONDS);
            }
            /**
             * 异步调用 数据库更新 用户信息
             */
            Future<Boolean> a = asyncTask.doLoin(request,redisUserInfo);
        } catch (JsonProcessingException e) {
            log.error("[用户登录] 登录javabean转json错误...");
            e.printStackTrace();
        }
        return redisUserInfo;
    }

}
